#include <stdio.h>

#include <openssl/err.h>
#include <openssl/pem.h>

#include "trace.h"
#include "util.h"

#define MAX_SIG_LEN (1000u)
#define ERR_BUF_SIZE            300

int verif_sig_file(const char *filename,
        const char *sig_file,
        const char *pub_key_pem_file){
    int ret_code = 0;

    if((NULL == filename) || (NULL == sig_file) ||
            (NULL == pub_key_pem_file)){
        TRACE_ERROR("Invalid input parameters\n");
        return 1;
    }

    // Step 1 - load public key from file
    DSA *dsa = NULL;
    if(load_public_key_dsa(pub_key_pem_file, &dsa)){
        TRACE_ERROR("load_public_key_dsa fail\n");
        return 1;
    }

    // Step 2 - compute sha1 hash of the file
    unsigned char *hash = (unsigned char *)malloc(SHA_DIGEST_LENGTH);
    if(NULL == hash) {
        TRACE_ERROR("malloc error\n");
        return 3;
    }

    unsigned int hash_len;
    if(calc_sha1(filename, &hash, &hash_len)){
        TRACE_ERROR("calc_sha1 error\n");
        return 3;
    }

    if(traceLevel >= TRACE_LEVEL_INFO){
        printf("SHA1(%s)=", filename);
        for(unsigned int i = 0; i < hash_len; i++){
            printf("%02x", hash[i]);
        }
        printf("\n");
    }

    // Step 3 - load signature to verify
    BIO *in = NULL;
    in = BIO_new(BIO_s_file());
    if(in == NULL) {
        TRACE_ERROR("BIO_new error\n");
        return 1;
    }

    if(!BIO_read_filename(in, (char*)sig_file)) {
        TRACE_ERROR("BIO_read_filename error for file: %s\n", sig_file);
        return 2;
    }

    unsigned char *signature = (unsigned char *)malloc(MAX_SIG_LEN);
    int signature_len = BIO_read(in, signature, MAX_SIG_LEN);

    if(signature_len <= 0) {
        TRACE_ERROR("problem reading signature from file\n");
        return 1;
    }

    DSA_SIG *dsa_sig = DSA_SIG_new();
    if(dsa_sig == NULL) {
        TRACE_ERROR("DSA_SIG_new fail\n");
        return 1;
    }

    if(NULL == d2i_DSA_SIG(&dsa_sig, (const unsigned char **) &signature,
            signature_len)){
        TRACE_ERROR("Decoding signature problem\n");
        return 1;
    }

    // Step 4 - verify signature
    int verif_code = DSA_do_verify(hash, hash_len, dsa_sig, dsa);
    if(0 == verif_code){
        TRACE_WARNING("Incorrect signature\n");
        ret_code = 1;
    }
    else if(-1 == verif_code){
        // error verifying signature
        char buf[ERR_BUF_SIZE];
        unsigned long errcode = ERR_get_error();

        ERR_load_crypto_strings();
        ERR_error_string(errcode, buf);
        TRACE_ERROR("\nDSA_do_verify error: %s\n", buf);
        ERR_free_strings();
    }
    else {
        // verif_code == 1
        TRACE_THIS("Signature of file %s is verified\n", filename);
    }

    BIO_free(in);

    DSA_SIG_free(dsa_sig);

    return ret_code;
}
